<?php
/**
* Parse a given QIF file and load the transactions in the DB.
* QIF format is line based with each line being one of the following:
* 
* ^ end of items, D date, T amount, C cleared, P payee, M memo, A address, L category, S cartegory split, E memo split, $ amount split
* 
*  @author       Fabrice Douteaud <clearbudget@douteaud.com>
* @package      actions
* @access       public
*/

/***********************************************************************

  Copyright (C) 2008  Fabrice douteaud (clearbudget@douteaud.com)

    This file is part of ClearBudget.

    ClearBudget is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    ClearBudget is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with ClearBudget.  If not, see <http://www.gnu.org/licenses/>.


************************************************************************/
//prevent direct access
if(!defined('ENGINEON')) die('Direct access forbidden');
global $context;
$db = class_db::getInstance();

// First we check if we have the correct data from the client
// check if we get there from a POST with a file uploaded
if($_SERVER["REQUEST_METHOD"] != 'POST' || !isset($_FILES["qiffile"])) {
  $return['error'] = true;
  $return['msg'] = $keys->error_ImproperCall;
  class_debug::addMsg(__FILE__, 'called to upload file not in POST and no file is present', DEBUGINFO);
  return;
  }

// check if the file has been uploaded correctly
if(!file_exists($_FILES["qiffile"]['tmp_name'])) {
  $return['error'] = true;
  $return['msg'] = $keys->error_ImproperQifFile;
  return;
  }

/**
	* clean the amount as to always have a valid float 
	*  	
	* @param string the amount
	* @return float the clean amount
	*/		
function cleanAmount($amount){
  $amount = trim($amount);
  if(preg_match("~^([0-9]+|(?:(?:[0-9]{1,3}([.,' ]))+[0-9]{3})+)(([.,])[0-9]{1,2})?$~", $amount, $r)){
    if(!empty($r['2'])){
      $pre = preg_replace("~[".$r['2']."]~", "", $r['1']);
      }
    else {
      $pre = $r['1'];
      }
    if(!empty($r['4'])){
      $post = ".".preg_replace("~[".$r['4']."]~", "", $r['3']);
      }
    else {
      $post = false;
      }
    $amount = $pre.$post;
    return $amount;
    }
  return false;
  }

/**
	* clean a string from any extra white spaces 
	*  	
	* @param string the string
	* @return string the clean string
	*/	
function clean($string) {
  $string = strtolower(trim($string));
  while(1) {
    $tmp = str_replace('  ', ' ', $string);
    if($tmp != $string) $string = $tmp;
    else break;
    }
  return $string; 
  }

// load the file in an array
$lines = @file($_FILES["qiffile"]['tmp_name']);
// if loading was unsuccessful, we exit with error (file type not correct most probably)
if($lines == false) {
  $return['error'] = true;
  $return['msg'] = $keys->error_ImproperQifFile2;
  return;
  }
// check if the first line starts with '!Type:' which should be the case in a valid QIF file
if(substr($lines[0], 0, 6) != '!Type:') {
  $return['error'] = true;
  $return['msg'] = $keys->error_ImproperQifFile3;
  return;
  }

// array to hold each item from the file
$item = array();
// counter of lines processed
$lineCounter = 1;
// counter of item inserted successfuly
$insertCounter = 0;  
// array to hold and compare magic number (but still allows n equal fields per file)
$magics = array();
// get today's date
$today = date("Y-m-d");
// clean the statement
$stmt = null;
// go line by line to process the file
foreach($lines as $line) {
  $lineCounter++;
  if($line != '') {
    // get the line identifier
    $id = substr($line, 0, 1);
    // get the content of that line
    $content = trim(substr($line, 1, strlen($line)));
    switch ($id) {
      case '^':
        set_time_limit(10); 
        // add the null category
        $item['category'] = '1';
        // add the current date
        $item['createDate'] = $today;
        // create the magic string
        $magic = $item['operationDate'].$item['amount'].$item['payee'];
        //echo '$magic: '.$magic.'<br/>';
        $magics[$magic][] = $lineCounter;
        $magicCounter = count($magics[$magic]);
        //echo '$magicCounter: '.$magicCounter.'<br/>';
        if($magicCounter > 1) {
          // add the checksum from the magic + the magic counter
          $item['checksum'] = md5($magic).'-'.$magicCounter;
          }
        else {
          // add the checksum from the magic
          $item['checksum'] = md5($magic);
          }
        
        // insert the row
        foreach($item as $field=>$value) {
          $db->addFields($field, $value);
          }
        
        if($db->insert('t_items', $stmt) !== false) {
          //echo 'inserted<br/>';
          $insertCounter++;
          }
        else {
          $magics[$magic] = null;
          }
        $item = null;
      break;
      case 'D':
        if($content == '') continue;
        // reformat the date as to get YYYY/MM/DD
        $date = explode('/', $content);
        // if date aren't splitted by /, we try with -
        if(is_array($date) && $date[0] == $content) $date = explode('-', $content);
        // if date array != 3, this is not normal so we skip this one
        if(count($date) != 3) {
          // if no date then it is january 01 2000 ... just because :-)
          $item['operationDate'] = '2000-01-01';
          continue;
          }
        // if year is on 2 digit we fake it to a year 2000 something
        if(strlen($date[2]) == 2) $date[2] = '20'.$date[2];
        // add the date
        $item['operationDate'] = $date[2].'-'.$date[1].'-'.$date[0];
      break;
      case 'T':
        $item['debit'] = '0';
        if($content == '') continue;
        $st = substr($content, 0, 1);
        if($st == '-') {
          $item['debit'] = '1';
          $content = substr($content, 1, strlen($content)-1);
          }
        $item['amount'] = cleanAmount($content);
      break;
      case 'C':
        $item['cleared'] = $content;
      break;
      case 'P':
        $item['payee'] = clean($content);
      break;
      case 'M':
        $item['memo'] = clean($content);
      break;
      default:
      break;
      } // switch
    } // if
  } // foreach


// let's update the time range if that has changed from the new data
$report = class_report::getInstance();
$report->setLimitMonth($context->range, true);

$return['msg'] = sprintf(' ('.$keys->text_pageUploadQifResultCount.' %d)', $insertCounter);
$return['error'] = false;
?>